// C++ Templates 14.3.2 实例化点（Points of Instantiation）

// 实例化点的概念
// 实例化点（Point of Instantiation，简称POI）是C++编译器决定生成模板实例的具体代码位置。这是模板编译过程中的一个关键概念，
// 它决定了：
// 1.哪些名称在模板实例化时可见
// 2.模板实例化的顺序
// 3.模板代码的查找范围

// 1.实例化点的确定规则
// C++标准对实例化点有明确的定义规则：
// 1.1对于函数模板
// 函数模板的实例化点位于该函数模板被引用的最近的命名空间作用域声明或定义之后，但在当前编译单元的末尾之前。
template <typename T>
T max(T a, T b) { return a > b ? a : b; }

void foo()
{
    int m = max(1, 2); // max<int>的引用点
    // max<int>的实例化点在这里
}

// 在编译单元结束前，max<int>必须被实例化

// 1.2对于类模板
// 类模板的成员函数的实例化点遵循以下规则：
// 1)如果成员函数在类模板外部定义，实例化点在该成员函数定义之后
// 2)如果成员函数在类模板内部定义，实例化点在该类模板被使用的点之后
template <typename T>
class MyClass
{
public:
    void foo() { /* 内联定义 */ }
    void bar();
};

template <typename T>
void MyClass<T>::bar() { /* 外部定义 */ }
// MyClass<T>::bar的实例化点在这里

void test()
{
    MyClass<int> obj;
    obj.foo(); // MyClass<int>::foo的引用点
    // MyClass<int>::foo的实例化点在这里
}

// 2.实例化点的重要性
// 实例化点的概念对于理解以下问题至关重要：
// <1> 名称查找（Name Lookup）
// 非依赖名称查找：在模板定义时进行
// 依赖名称查找：在实例化点进行
template <typename T>
void func()
{
    X x;       // 非依赖名称，在模板定义时查找
    T::type y; // 依赖名称，在实例化点查找
}

// <2> ADL（Argument-Dependent Lookup）
// 实例化点影响参数依赖查找的结果：
namespace N
{
    struct S
    {
    };
    template <typename T>
    void foo(T) { bar(T()); } // bar通过ADL查找
}

void bar(N::S) {} // 在全局命名空间定义bar

void test()
{
    N::foo(N::S()); // 实例化N::foo<N::S>
    // 在这个实例化点，bar(N::S)通过ADL可见
}

// <3> 实例化顺序和循环依赖
// 实例化点规则有助于解决模板间的循环依赖问题：
template <typename T>
class X;
template <typename T>
class Y;

template <typename T>
class X
{
    Y<T> *y; // 引用Y<T>，但不需要完整定义
public:
    void f() { y->g(); } // 需要Y<T>的完整定义
};

template <typename T>
class Y
{
    X<T> *x; // 引用X<T>，但不需要完整定义
public:
    void g() { x->f(); } // 需要X<T>的完整定义
};
// 如果没有明确的实例化点规则，这里会有循环依赖问题

// 3.显式控制实例化点
// C++提供了机制来显式控制模板的实例化：
// <1>显式实例化声明（Explicit Instantiation Declaration）
extern template class std::vector<int>; // 声明但不定义
// 这告诉编译器在当前编译单元中不要实例化该模板，而是在其他地方寻找其定义。

// <2>显式实例化定义（Explicit Instantiation Definition）
template class std::vector<int>; // 强制在此处实例化
// 这强制编译器在指定位置实例化模板，无论它是否被使用。

// 这强制编译器在指定位置实例化模板，无论它是否被使用。

// 4.实际应用
// 理解实例化点对于以下场景非常重要：
// 1)减少编译时间：通过控制实例化点，可以减少重复实例化
// 2)减少编译时间：通过控制实例化点，可以减少重复实例化
// 3)调试复杂模板：知道模板在哪里实例化有助于调试
// 4)优化头文件组织：合理组织头文件可以控制实例化点

// 5.总结
// 实例化点是C++ 模板系统中的一个核心概念，它决定了模板代码何时何地被生成。理解实例化点规则有助于编写更健壮的模板代码，避免常见的模板相关错误，并优化编译性能。
